package oss

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/gin-gonic/gin"
	"myai/core/types"
	"myai/utils"
	"net/url"
	"path/filepath"
	"strings"
	"time"
)

type AliYunOss struct {
	config   *types.AliYunOssConfig
	bucket   *oss.Bucket
	proxyURL string
}

func NewAliYunOss(appConfig *types.AppConfig) (*AliYunOss, error) {
	config := &appConfig.OSS.AliYun
	// 创建OSS客户端
	client, err := oss.New(config.Endpoint, config.AccessKey, config.AccessSecret)
	if err != nil {
		return nil, err
	}
	// 获取存储空间
	bucket, err := client.Bucket(config.Bucket)
	if err != nil {
		return nil, err
	}
	// 设置目录
	if config.SubDir == "" {
		config.SubDir = "gpt"
	}
	return &AliYunOss{
		config:   config,
		bucket:   bucket,
		proxyURL: appConfig.ProxyURL,
	}, nil
}

func (s *AliYunOss) PutFile(ctx *gin.Context, name string) (File, error) {
	// 解析表单
	file, err := ctx.FormFile(name)
	if err != nil {
		return File{}, err
	}
	// 打开上传的文件
	src, err := file.Open()
	if err != nil {
		return File{}, err
	}
	defer src.Close()
	// 获取文件扩展名
	fileExt := filepath.Ext(file.Filename)
	// 文件完整存储目录
	objectKey := fmt.Sprintf("%s/%d%s", s.config.SubDir, time.Now().UnixMicro(), fileExt)
	// 上传文件
	err = s.bucket.PutObject(objectKey, src)
	if err != nil {
		return File{}, err
	}
	return File{
		Name:   file.Filename,
		ObjKey: objectKey,
		URL:    fmt.Sprintf("%s/%s", s.config.Domain, objectKey),
		Ext:    fileExt,
		Size:   file.Size,
	}, nil
}

func (s *AliYunOss) PutUrlFile(fileURL string, useProxy bool) (string, error) {
	var fileData []byte
	var err error
	// 下载文件返回字节数据
	if useProxy {
		fileData, err = utils.DownloadImg(fileURL, s.proxyURL)
	} else {
		fileData, err = utils.DownloadImg(fileURL, "")
	}
	if err != nil {
		return "", fmt.Errorf("下载图片文件出现错误：%v", err)
	}
	parse, err := url.Parse(fileURL)
	if err != nil {
		return "", fmt.Errorf("解析文件地址出错：%v", err)
	}
	// 获取文件扩展名
	fileExt := utils.GetImgExt(parse.Path)
	// 拼接完整的文件上传地址
	objectKey := fmt.Sprintf("%s/%d%s", s.config.SubDir, time.Now().UnixMicro(), fileExt)
	// 上传文件字节数据
	err = s.bucket.PutObject(objectKey, bytes.NewReader(fileData))
	if err != nil {
		return "", err
	}
	// 返回文件的访问地址
	return fmt.Sprintf("%s/%s", s.config.Domain, objectKey), nil
}

func (s *AliYunOss) PutBase64(base64Img string) (string, error) {
	imageData, err := base64.StdEncoding.DecodeString(base64Img)
	if err != nil {
		return "", fmt.Errorf("图片base64数据解码失败：%v", err)
	}
	objectKey := fmt.Sprintf("%s/%d.png", s.config.SubDir, time.Now().UnixMicro())
	// 上传文件字节数据
	err = s.bucket.PutObject(objectKey, bytes.NewReader(imageData))
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s/%s", s.config.Domain, objectKey), nil
}

func (s *AliYunOss) Delete(fileURL string) error {
	var objectKey string
	// 判断前缀是否以http开头
	if strings.HasPrefix(fileURL, "http") {
		// 获取文件名称
		// filepath.Base(fileURL) 的作用是从文件路径中提取最后一个元素（通常是文件名部分）
		filename := filepath.Base(fileURL)
		objectKey = fmt.Sprintf("%s/%s", s.config.SubDir, filename)
	} else {
		objectKey = fileURL
	}
	return s.bucket.DeleteObject(objectKey)
}

var _ Uploader = &AliYunOss{}
